﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks;

namespace OF.Lib.DataAccess.Core
{
    internal class LocalMemoryCacheHelper 
    { 
        static readonly NamedReaderWriterLocker _namedRwlocker = new NamedReaderWriterLocker();

        public T GetWithCache<T>(string cacheKey, Func<T> getter, int cacheTimeSecond, bool absoluteExpiration = true)
            where T : class
        {
            T rst = null;
            //有缓存则直接读缓存
            var rwLock = _namedRwlocker.GetLock(cacheKey);
            try
            {
                rwLock.EnterReadLock();
                rst = MemoryCache.Default.Get(cacheKey) as T;
                if (rst != null)
                {
                    return rst;
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            //无缓存则直接处理并写入缓存
            try
            {
                rwLock.EnterWriteLock();
                rst = MemoryCache.Default.Get(cacheKey) as T;
                if (rst != null)
                {
                    return rst;
                }
                rst = getter();
                CacheItemPolicy cp = new CacheItemPolicy();
                if (absoluteExpiration)
                {
                    cp.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(cacheTimeSecond));
                }
                else
                {
                    cp.SlidingExpiration = TimeSpan.FromSeconds(cacheTimeSecond);
                }
                if (rst != null)
                {
                    MemoryCache.Default.Set(cacheKey, rst, cp);
                }
                return rst; 
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }

        public object GetWithCache(string cacheKey, Func<object> getter, int cacheTimeSecond, bool absoluteExpiration = true)
        {
            object rst = null;
            //有缓存则直接读缓存
            var rwLock = _namedRwlocker.GetLock(cacheKey);
            try
            {
                rwLock.EnterReadLock();
                rst = MemoryCache.Default.Get(cacheKey);
                if (rst != null)
                {
                    return rst;
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            //无缓存则直接处理并写入缓存
            try
            {
                rwLock.EnterWriteLock(); 
                rst = MemoryCache.Default.Get(cacheKey);
                if (rst != null)
                {
                    return rst;
                }
                rst = getter();
                CacheItemPolicy cp = new CacheItemPolicy();
                if (absoluteExpiration)
                {
                    cp.AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(cacheTimeSecond));
                }
                else
                {
                    cp.SlidingExpiration = TimeSpan.FromSeconds(cacheTimeSecond);
                }
                if (rst != null)
                {
                    MemoryCache.Default.Set(cacheKey, rst, cp);
                }
                return rst; 
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

        }
        public void Remove(string key)
        {
            var rwLock = _namedRwlocker.GetLock(key);
            try
            {
                rwLock.EnterWriteLock();
                MemoryCache.Default.Remove(key);
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }

        public void FlushAll()
        {
            MemoryCache.Default.Dispose();
        }

        public IEnumerable<KeyValuePair<string, object>> GetList()
        {
            return MemoryCache.Default;
        }
    }
}
